'use strict';

const path = require('path');

const npminstall = require('npminstall');
const pathExists = require('path-exists').sync;
const fsExtra = require('fs-extra');
const pkgDir = require('pkg-dir').sync;

const log = require('@x3-cli-dev/log');
const npm = require('@x3-cli-dev/npm');
const { isObject, formatPath } = require('@x3-cli-dev/utils');

class Package {
  get cacheFilePath() {
    return this.getSpecificCacheFilePath(this.version);
  }

  constructor(options) {
    if (!options) {
      throw new Error('Package类的options参数不能为空！');
    }
    if (!isObject(options)) {
      throw new Error('Package类的options参数必须为对象！');
    }

    // package的目标路径
    this.targetPath = options.targetPath;
    // 缓存package的路径
    this.storeDir = options.storeDir;
    // package的name
    this.name = options.packageName;
    // package的version
    this.version = options.packageVersion;
    // package的缓存目录前缀
    this.cacheFilePathPrefix = this.name?.replace('/', '_');
  }

  async prepare() {
    // 确保 storeDir 已存在
    if (this.storeDir && !pathExists(this.storeDir)) {
      fsExtra.mkdirpSync(this.storeDir);
    }
    // 如果版本为 latest 则转换版本号
    if (this.version === 'latest') {
      this.version = await npm.getLatestVersion(this.name);
    }
  }

  async install(version) {
    await this.prepare();
    await npminstall({
      root: this.targetPath,
      storeDir: this.storeDir,
      pkgs: [{ name: this.name, version: version ?? this.version }],
      registry: npm.getNpmRegistry(),
    });
  }

  /**
   * 判断 Package 是否存在
   */
  async exist() {
    // 存在缓存目录，就不是通过 target-path 指定
    if (this.storeDir) {
      await this.prepare();
      log.verbose('cacheFilePath', this.cacheFilePath);
      return pathExists(this.cacheFilePath);
    } else {
      return pathExists(this.targetPath);
    }
  }

  async update() {
    await this.prepare();
    // 1. 获取最新的npm模块版本号
    const latestPackageVersion = await npm.getLatestVersion(this.name);
    // 2. 查询最新版本号对应的路径是否存在
    const latestFilePath = this.getSpecificCacheFilePath(latestPackageVersion);
    // 3. 不存在安装最新版本
    if (!pathExists(latestFilePath)) {
      await this.install(latestPackageVersion);
    }
    this.version = latestPackageVersion;
  }

  /**
   * 拼接缓存路径
   * _@x3-cli-dev_init@1.0.1@x3-cli-dev/init
   */
  getSpecificCacheFilePath(packageVersion) {
    return path.resolve(
      this.storeDir,
      `_${this.cacheFilePathPrefix}@${packageVersion}@${this.name}`
    );
  }

  /**
   * 获取入口文件
   */
  getRootFilePath() {
    const getRootFile = (targetPath) => {
      const dir = pkgDir(targetPath);
      const pkgFile = require(path.resolve(targetPath, 'package.json'));
      if (pkgFile && pkgFile.main) {
        // 路径兼容（windows/macOS)
        return formatPath(path.resolve(dir, pkgFile.main));
      }
      return null;
    }

    // 不是指定 target-path
    if (this.storeDir) {
      return getRootFile(this.cacheFilePath);
    } else {
      return getRootFile(this.targetPath);
    }
  }
}

module.exports = Package;
